package com.alageek.crowd.mvc.config;

import com.alageek.crowd.constant.CrowdConstant;
import com.alageek.crowd.exception.AccessForbiddenException;
import com.alageek.crowd.exception.AdminAddFailedException;
import com.alageek.crowd.exception.AdminEditFailedException;
import com.alageek.crowd.exception.LoginFailedException;
import com.alageek.crowd.util.CrowdUtil;
import com.alageek.crowd.util.ResultEntity;
import com.google.gson.Gson;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


/**
 * 异常处理机制
 * @author alageek
 * 注解ControllerAdvice表示当前类是基于注解的异常处理器类
 */
@ControllerAdvice
public class CrowdExceptionResolver {

    /**
     * 修改数据失败异常处理
     * 注解ExceptionHandler将异常类与方法关联
     * @param exception 异常对象
     * @param request   请求对象
     * @param response  响应对象
     * @return 若请求为Ajax请求，则返回json类型的错误信息，否则返回错误页面
     * @throws IOException ResultEntity对象转json异常
     */
    @ExceptionHandler(value = AdminEditFailedException.class)
    public ModelAndView resolveAdminEditFailedException(
            AdminEditFailedException exception,
            HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        String viewName = "admin-edit";
        return commonResolve(exception, request, response, viewName);
    }

    /**
     * 添加数据失败异常处理
     * 注解ExceptionHandler将异常类与方法关联
     * @param exception 异常对象
     * @param request   请求对象
     * @param response  响应对象
     * @return 若请求为Ajax请求，则返回json类型的错误信息，否则返回错误页面
     * @throws IOException ResultEntity对象转json异常
     */
    @ExceptionHandler(value = AdminAddFailedException.class)
    public ModelAndView resolveAdminAddFailedException(
            AdminAddFailedException exception,
            HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        String viewName = "admin-add";
        return commonResolve(exception, request, response, viewName);
    }

    /**
     * 禁止访问异常处理
     * 注解ExceptionHandler将异常类与方法关联
     * @param exception 异常对象
     * @param request   请求对象
     * @param response  响应对象
     * @return 若请求为Ajax请求，则返回json类型的错误信息，否则返回错误页面
     * @throws IOException ResultEntity对象转json异常
     */
    @ExceptionHandler(value = AccessForbiddenException.class)
    public ModelAndView resolveAccessForbiddenException(
            AccessForbiddenException exception,
            HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        String viewName = "admin-login";
        return commonResolve(exception, request, response, viewName);
    }

    /**
     * 登录失败异常处理
     * 注解ExceptionHandler将异常类与方法关联
     * @param exception 异常对象
     * @param request   请求对象
     * @param response  响应对象
     * @return 若请求为Ajax请求，则返回json类型的错误信息，否则返回错误页面
     * @throws IOException ResultEntity对象转json异常
     */
    @ExceptionHandler(value = LoginFailedException.class)
    public ModelAndView resolveLoginFailedException(
            LoginFailedException exception,
            HttpServletRequest request,
            HttpServletResponse response) throws IOException {
        String viewName = "admin-login";
        return commonResolve(exception, request, response, viewName);
    }

    /**
     * 其他失败异常处理
     * 注解ExceptionHandler将异常类与方法关联
     * @param exception 异常对象
     * @param request   请求对象
     * @param response  响应对象
     * @return 若请求为Ajax请求，则返回json类型的错误信息，否则返回错误页面
     * @throws IOException ResultEntity对象转json异常
     */
    @ExceptionHandler(value = Exception.class)
    public ModelAndView resolveException(
            Exception exception,
            HttpServletRequest request,
            HttpServletResponse response ) throws IOException {
        String viewName = "system-error";
        return commonResolve(exception, request, response, viewName);
    }

    private ModelAndView commonResolve(
            Exception exception,
            HttpServletRequest request,
            HttpServletResponse response,
            String viewName) throws IOException {
        if(CrowdUtil.judgeRequestType(request)){
            // Ajax请求
            response.getWriter().write(new Gson().toJson(ResultEntity.failed(exception.getMessage())));
            return null;
        }
        // 普通请求
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject(CrowdConstant.ATTR_NAME_EXCEPTION, exception);
        modelAndView.setViewName(viewName);
        return modelAndView;
    }

}
